package com.central.common.utils

import cn.hutool.core.date.DateUtil
import cn.hutool.core.util.IdUtil
import com.alibaba.fastjson.JSONObject
import java.time.LocalDateTime
import java.time.ZoneId
import java.util.*
import kotlin.math.acos
import kotlin.math.cos
import kotlin.math.sin


data class PageModel(var page: Int? = 1, var pageSize: Int? = 10, var userId: String? = null)


fun nextId() = IdUtil.createSnowflake(1,1).nextId().toString()



fun String.toJsonObject(): JSONObject = JSONObject.parseObject(this)

/**
 * 分页
 */
fun <T> List<T>.toPage(page: Int, pageSize: Int): List<T> = this.takeIf { it.isNotEmpty() }?.run {

    when {
        this.size < (page - 1)* pageSize -> emptyList()
        (page - 1)* pageSize < this.size && this.size < page * pageSize - 1 -> this.slice((page - 1)* pageSize until this.size)
        else -> this.slice((page - 1)* pageSize until page * pageSize)
    }
} ?: emptyList()

inline fun <T, R> MutableList<T>.toListVo(transform: (T) -> (R?)): MutableList<R> =  this.mapNotNull { transform(it) }.toMutableList()


data class Point2D( var longitude: Double? = 0.0, var latitude: Double? = 0.0)


// 平均半径,单位：m
const val EARTH_RADIUS: Double = 6371393.0
fun getDistance(pointA: Point2D, pointB: Point2D): Double {

    if (pointB.longitude == null || pointB.latitude == null || pointA.latitude == null || pointA.longitude == null) {
        return 0.0
    }
    // 经纬度（角度）转弧度。弧度用作参数，以调用Math.cos和Math.sin
    // 经纬度（角度）转弧度。弧度用作参数，以调用Math.cos和Math.sin
    val radiansAX = Math.toRadians(pointA.longitude!!) // A经弧度

    val radiansAY = Math.toRadians(pointA.latitude!!) // A纬弧度

    val radiansBX = Math.toRadians(pointB.longitude!!) // B经弧度

    val radiansBY = Math.toRadians(pointB.latitude!!) // B纬弧度

    val cos = (cos(radiansAY) * cos(radiansBY) * cos(radiansAX - radiansBX)
            + sin(radiansAY) * sin(radiansBY))

    val acos = acos(cos) // 反余弦值

    return EARTH_RADIUS * acos // 最终结果
}

const val ONE_MINUTE = 60000L
const val ONE_HOUR = 3600000L
const val ONE_DAY = 86400000L
const val ONE_WEEK = 604800000L

const val ONE_SECOND_AGO = "秒前"
const val ONE_MINUTE_AGO = "分钟前"
const val ONE_HOUR_AGO = "小时前"
const val ONE_DAY_AGO = "天前"
const val ONE_MONTH_AGO = "月前"
const val ONE_YEAR_AGO = "年前"


fun toSeconds(date: Long): Long {
    return date / 1000L
}

fun toMinutes(date: Long): Long {
    return toSeconds(date) / 60L
}

fun toHours(date: Long): Long {
    return toMinutes(date) / 60L
}

fun toDays(date: Long): Long {
    return toHours(date) / 24L
}

fun toMonths(date: Long): Long {
    return toDays(date) / 30L
}

fun toYears(date: Long): Long {
    return toMonths(date) / 365L
}


fun Date.format(): String {

    val delta: Long = Date().time - this.time
    if (delta < ONE_MINUTE) {
        val seconds: Long = toSeconds(delta)
        return (if (seconds <= 0) 1 else seconds).toString() + ONE_SECOND_AGO
    }
    if (delta < 45L * ONE_MINUTE) {
        val minutes: Long = toMinutes(delta)
        return (if (minutes <= 0) 1 else minutes).toString() + ONE_MINUTE_AGO
    }
    if (delta < 24L * ONE_HOUR) {
        val hours: Long = toHours(delta)
        return (if (hours <= 0) 1 else hours).toString() + ONE_HOUR_AGO
    }
    if (delta < 48L * ONE_HOUR) {
        return "昨天"
    }
    if (delta < 30L * ONE_DAY) {
        val days: Long = toDays(delta)
        return (if (days <= 0) 1 else days).toString() + ONE_DAY_AGO
    }
    return if (delta < 12L * 4L * ONE_WEEK) {
        val months: Long = toMonths(delta)
        (if (months <= 0) 1 else months).toString() + ONE_MONTH_AGO
    } else {
        val years: Long = toYears(delta)
        (if (years <= 0) 1 else years).toString() + ONE_YEAR_AGO
    }
}

infix fun Int.toDateBegin(month: Int): Date = Date.from(
    LocalDateTime.of(
        this, month, 1,
        0, 0, 0
    ).atZone(ZoneId.systemDefault()).toInstant()
)

infix fun Int.toDateEnd(month: Int): Date = when(month) {

    2 -> Date.from(
        LocalDateTime.of(
            this, month, 28,
            23, 59, 59
        ).atZone(ZoneId.systemDefault()).toInstant()
    )
    1,3,5,7,8,10,12 -> Date.from(
        LocalDateTime.of(
            this, month, 31,
            23, 59, 59
        ).atZone(ZoneId.systemDefault()).toInstant()
    )
    else -> Date.from(
        LocalDateTime.of(
            this, month, 30,
            23, 59, 59
        ).atZone(ZoneId.systemDefault()).toInstant()
    )
}

fun Int.weekStr(day: Int, year: Int): Int {

    val cal = Calendar.getInstance()
    cal.time =  Date.from(
        LocalDateTime.of(
            year, this, day,
            0, 0, 0
        ).atZone(ZoneId.systemDefault()).toInstant())
   return when (val w = cal.get(Calendar.DAY_OF_WEEK) - 1) {
        0 -> 7
        else -> w
    }
}

fun Date.formatStandard(): String = DateUtil.format(this, "yyyy-MM-dd HH:mm:ss")

fun main() {

    println(Date().formatStandard())
    println(5.weekStr(31, 2021))
}
